package com.sos.config
{

	import com.sos.data.adapters.ConfigurationAdapter;
	import com.sos.logging.Logger;
	import com.sos.utils.JsonUtils;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;

	public class ConfigurationManager implements IEventDispatcher
	{

		// -------------------------------------------------------------------------------
		// CONSTANTS
		// -------------------------------------------------------------------------------
				
		// -------------------------------------------------------------------------------
		// FIELDS
		// -------------------------------------------------------------------------------
		
		private var _executing:Boolean;
		private var _loader:URLLoader;
		private var _dispatcher:EventDispatcher;
		
		// -------------------------------------------------------------------------------
		// CONSTRUCTOR
		// -------------------------------------------------------------------------------
		
		public function ConfigurationManager()
		{
			// Data init
			_executing = false;
			// Obejct init
			_loader = new URLLoader();
			_dispatcher = new EventDispatcher(this);
			// Event handlers setup
			_loader.addEventListener(Event.COMPLETE, loaderComplete);
			_loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loaderSecurityError);
			_loader.addEventListener(IOErrorEvent.IO_ERROR, loaderIOError);
		}
		
		// -------------------------------------------------------------------------------
		// PROPERTIES
		// -------------------------------------------------------------------------------
		
		/**
		 * Checks if the ConfigurationManager is loading cards 
		 * @return true if the card manager is loading data
		 */
		public function get isLoading():Boolean
		{
			return _executing;
		}
		
		// -------------------------------------------------------------------------------
		// PRIVATE METHODS
		// -------------------------------------------------------------------------------
		
		// UrlLoader event handlers
		
		protected function loaderComplete(event:Event):void
		{
			try
			{
				// Retrieve the url loader
				var loader:URLLoader = event.target as URLLoader;
				// create the configuration using the adaper
				var config:Configuration = ConfigurationAdapter.fromXML(new XML(loader.data));
				// Dispatch ConfigurationManager.EVENT_LOAD_COMPLETED event 
				dispatchLoadCompleted(config);
			}
			catch (err:Error)
			{
				// DEBUG > Unexpected error
				Logger.error("ConfigurationManager.loaderComplete() unexpected error", err);
				// Dispatch ConfigurationManager.EVENT_LOAD_FAILED event 
				dispatchLoadFailed("ConfigurationManager.loaderComplete() unexpected error: " + err.message);
			}
		}
		
		protected function loaderIOError(e:IOErrorEvent):void
		{
			try
			{
				// Dispatch ConfigurationManager.EVENT_LOAD_FAILED event 
				dispatchLoadFailed("ConfigurationManager data loading failed: " + e.text);
			}
			catch (err:Error)
			{
				// DEBUG > Unexpected error
				Logger.error("ConfigurationManager.loaderIOError() unexpected error", err);
				// Dispatch ConfigurationManager.EVENT_LOAD_FAILED event 
				dispatchLoadFailed("ConfigurationManager.loaderIOError() unexpected error: " + err.message);
			}
		}
		
		protected function loaderSecurityError(e:SecurityErrorEvent):void
		{
			try
			{
				// Dispatch ConfigurationManager.EVENT_LOAD_FAILED event 
				dispatchLoadFailed("ConfigurationManager data loading failed: " + e.text);
			}
			catch (error:Error)
			{
				// DEBUG > Unexpected error
				Logger.error("ConfigurationManager.loaderSecurityError() unexpected error", error);
				// Dispatch ConfigurationManager.EVENT_LOAD_FAILED event 
				dispatchLoadFailed("ConfigurationManager.loaderSecurityError() unexpected error: " + error.message);
			}	
		}
		
		// Events dispatcher
		
		/**
		 * Dispatch ConfigurationManager.EVENT_LOAD_STARTED event 
		 */
		protected function dispatchLoadStarted():void
		{
			dispatchEvent(new ConfigurationManagerEvent(ConfigurationManagerEvent.EVENT_LOAD_STARTED, this));
		}
		
		/**
		 * Dispatch ConfigurationManager.EVENT_LOAD_CANCELLED event 
		 */
		protected function dispatchLoadCancelled():void
		{
			dispatchEvent(new ConfigurationManagerEvent(ConfigurationManagerEvent.EVENT_LOAD_CANCELLED, this, "Card data loading cancelled by the user"));
		}
		
		/**
		 * Dispatch ConfigurationManager.EVENT_LOAD_COMPLETED event 
		 */		
		protected function dispatchLoadCompleted(config:Configuration):void
		{
			dispatchEvent(new ConfigurationManagerEvent(ConfigurationManagerEvent.EVENT_LOAD_COMPLETED, this, "", config));
		}
		
		/**
		 * Dispatch ConfigurationManager.EVENT_LOAD_FAILED event 
		 */
		protected function dispatchLoadFailed(errorMessage:String):void
		{
			dispatchEvent(new ConfigurationManagerEvent(ConfigurationManagerEvent.EVENT_LOAD_FAILED, this, errorMessage));
		}		
		
		// -------------------------------------------------------------------------------
		// PUBLIC METHODS
		// -------------------------------------------------------------------------------
				
		/**
		 * Loads the configuration using given parameters  
		 */		
		public function load(url:String):void
		{
			// Raises the executiong flag
			_executing = true;
			// Dispatch EVENT_LOAD_STARTED
			dispatchLoadStarted();
			// Starts to load
			_loader.load(new URLRequest(url));
		}
		
		/**
		 * Cancels the current configuration loading  
		 */		
		public function cancel():void
		{
			if (_executing)
			{
				_loader.close();
			}
			// Dispatch EVENT_LOAD_CANCELLED
			dispatchLoadCancelled();
		}
		
		// IEventDispatcher implementation
		
		public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
		{
			_dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
		}
		
		public function dispatchEvent(event:Event):Boolean
		{
			return _dispatcher.dispatchEvent(event);
		}
		
		public function hasEventListener(type:String):Boolean
		{
			return _dispatcher.hasEventListener(type);
		}
		
		public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
		{
			_dispatcher.removeEventListener(type, listener, useCapture);
		}
		
		public function willTrigger(type:String):Boolean
		{
			return _dispatcher.willTrigger(type);
		}
		
	}
}